package cn.sdormitory.component.bindValue;

import cn.hutool.core.convert.Convert;
import cn.sdormitory.common.utils.ContainerUtil;
import cn.sdormitory.component.bindValue.bean.info.BindInfo;
import cn.sdormitory.component.bindValue.bean.info.BindStoreInfo;
import cn.sdormitory.component.bindValue.bean.info.StoreInfo;
import com.google.common.collect.Table;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;

import java.util.List;
import java.util.Map;

@Component
@Slf4j
public class DefaultBindValueHelper extends AbstractBindValueHelper {
    @Override
    public void bindValue(Object res) {
        List<?> dataList = getResDataList(res);
        Class<?> dataClass = getDataClass(dataList);

        if(notSupport(dataClass) || ContainerUtil.isEmpty(dataList)){
            // dataClass不为空 不为集合 dataList不为空
            return;
        }

        List<BindInfo> bindInfos = getBindInfos(dataClass);
        bindInfos.forEach(bindInfo-> bindValue(bindInfo, dataList));

        List<StoreInfo> storeInfos = getStoreInfos(dataClass);
        storeInfos.forEach(storeInfo-> storeValue(dataClass,storeInfo, dataList));
    }

    private void storeValue(Class<?> dataClass, StoreInfo storeInfo, List<?> dataList) {
        AnnotationContext<StoreInfo, Table<String, String, Object>> context = generateAnnotationContextByStoreInfo(storeInfo, dataList);
        Table<String, String, Object> storeTable = context.invoke();
        if(ContainerUtil.isEmpty(storeTable)){
            return;
        }

        List<BindStoreInfo> bindStoreInfos = getBindStoreInfos(dataClass);
        bindStoreInfos.forEach(bindStoreInfo -> bindStoreValue(bindStoreInfo, storeTable, dataList));
    }

    private void bindStoreValue(BindStoreInfo bindStoreInfo,
                                Table<String, String, Object> storeTable,
                                List<?> dataList) {
        dataList.forEach(item -> {
            String rowKey = bindStoreInfo.getRowKey(item);
            Object value = storeTable.get(rowKey, bindStoreInfo.getColumnKey());
            bindStoreInfo.setItemValue(item, value);
        });

    }


    /**
     * 解析bindInfo为目标字段注入对应的值
     * @param bindInfo 绑定信息
     * @param list 待处理的数据列表
     */
    private void bindValue(BindInfo bindInfo, List<?> list) {
        AnnotationContext<BindInfo, Map<String, String>> context = generateAnnotationContextByBindInfo(bindInfo, list);
        Map<String, String> mapping = context.invoke();
        if(ContainerUtil.isEmpty(mapping)){
            return;
        }

        bindValue(bindInfo, list, mapping);
    }

    private static void bindValue(BindInfo bindInfo, List<?> list, Map<String, String> mapping) {
        // 根据mapping信息为目标字段注入值
        Object defaultValue = Convert.convert(bindInfo.getTargetField().getType(), bindInfo.getDefaultValue());
        ContainerUtil.forEach(list, item->{
            Object variableValue = ReflectionUtils.getField(bindInfo.getVariableField(), item);
            String targetValue = mapping.get(Convert.toStr(variableValue));
            if(targetValue==null && defaultValue!=null){
                Object targetValueByOld = ReflectionUtils.getField(bindInfo.getTargetField(), item);
                if(targetValueByOld == null){
                    ReflectionUtils.setField(bindInfo.getTargetField(),item,defaultValue);
                }
            }
            if(targetValue != null){
                ReflectionUtils.setField(bindInfo.getTargetField(),item,targetValue);
            }
        });
    }

}
